/**
 ** This file is part of the qt-opencv-learning project.
 ** Copyright 2021 add358 <add358@gmail.com>.
 **
 ** @brief base on [basic drawing](https://docs.opencv.org/4.5.3/d3/d96/tutorial_basic_geometric_drawing.html)
 **/

#include "basic_drawing.h"

#include <convert.h>

#include <QHBoxLayout>
#include <QLabel>

#include <opencv2/imgproc.hpp>

#define w 400

using namespace cv;

BasicDrawing::BasicDrawing(QWidget *parent)
    : QWidget(parent)
{
    auto atomLabel = new QLabel(this);
    atomLabel->setPixmap(QPixmap::fromImage(atom()));

    auto rookLabel = new QLabel(this);
    rookLabel->setPixmap(QPixmap::fromImage(rook()));

    auto h = new QHBoxLayout(this);
    h->addWidget(atomLabel);
    h->addWidget(rookLabel);
}

QImage BasicDrawing::atom() const
{
    Mat atom_image = Mat::zeros( w, w, CV_8UC3 );
    ellipse( atom_image, 90 );
    ellipse( atom_image, 0 );
    ellipse( atom_image, 45 );
    ellipse( atom_image, -45 );
    circle( atom_image, Point( w/2, w/2) );
    return cvMat2QImage(atom_image);
}

QImage BasicDrawing::rook() const
{
    Mat rook_image = Mat::zeros( w, w, CV_8UC3 );
    polygon( rook_image );
    rectangle( rook_image,
               Point( 0, 7*w/8 ),
               Point( w, w),
               Scalar( 0, 255, 255 ),
               FILLED,
               LINE_8);
    line( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) );
    line( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) );
    line( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) );
    line( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) );
    return cvMat2QImage(rook_image);
}

void BasicDrawing::ellipse( Mat img, double angle ) const
{
    int thickness = 2;
    int lineType = 8;
    cv::ellipse( img,
                 Point( w/2, w/2 ),
                 Size( w/4, w/16 ),
                 angle,
                 0,
                 360,
                 Scalar( 255, 0, 0 ),
                 thickness,
                 lineType );
}
void BasicDrawing::circle( Mat img, Point center ) const
{
    cv::circle( img,
                center,
                w/32,
                Scalar( 0, 0, 255 ),
                FILLED,
                LINE_8 );
}
void BasicDrawing::polygon( Mat img ) const
{
    int lineType = LINE_8;
    Point rook_points[1][20];
    rook_points[0][0]  = Point(    w/4,   7*w/8 );
    rook_points[0][1]  = Point(  3*w/4,   7*w/8 );
    rook_points[0][2]  = Point(  3*w/4,  13*w/16 );
    rook_points[0][3]  = Point( 11*w/16, 13*w/16 );
    rook_points[0][4]  = Point( 19*w/32,  3*w/8 );
    rook_points[0][5]  = Point(  3*w/4,   3*w/8 );
    rook_points[0][6]  = Point(  3*w/4,     w/8 );
    rook_points[0][7]  = Point( 26*w/40,    w/8 );
    rook_points[0][8]  = Point( 26*w/40,    w/4 );
    rook_points[0][9]  = Point( 22*w/40,    w/4 );
    rook_points[0][10] = Point( 22*w/40,    w/8 );
    rook_points[0][11] = Point( 18*w/40,    w/8 );
    rook_points[0][12] = Point( 18*w/40,    w/4 );
    rook_points[0][13] = Point( 14*w/40,    w/4 );
    rook_points[0][14] = Point( 14*w/40,    w/8 );
    rook_points[0][15] = Point(    w/4,     w/8 );
    rook_points[0][16] = Point(    w/4,   3*w/8 );
    rook_points[0][17] = Point( 13*w/32,  3*w/8 );
    rook_points[0][18] = Point(  5*w/16, 13*w/16 );
    rook_points[0][19] = Point(    w/4,  13*w/16 );
    const Point* ppt[1] = { rook_points[0] };
    int npt[] = { 20 };
    cv::fillPoly( img,
                  ppt,
                  npt,
                  1,
                  Scalar( 255, 255, 255 ),
                  lineType );
}
void BasicDrawing::line( Mat img, Point start, Point end ) const
{
    int thickness = 2;
    int lineType = LINE_8;
    cv::line( img,
              start,
              end,
              Scalar( 0, 0, 0 ),
              thickness,
              lineType );
}
